package com.tang.juc.ThreadCommunication;

/**
 * @author tlm
 * @version 1.0
 * @date 2020/3/19 10:34
 * 生产者消费者问题 Synchronized版
 * <p>
 * 线程之间的通信问题：生产者和消费者问题！ 等待唤醒，通知唤醒
 * 线程交替执行 A B 操作同一个变量 num = 0
 * A num+1
 * B num-1
 */
public class boundedBufferProblem1 {
    public static void main(String[] args) {
        Data data = new Data();
        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();

        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();
    }
    /*
    输出结果为:
A=>1
B=>0
A=>1
B=>0
A=>1
B=>0
A=>1
B=>0
A=>1
B=>0
A=>1
B=>0
A=>1
B=>0
A=>1
B=>0
A=>1
B=>0
A=>1
B=>0
     */
    /*
    现在只有A，B两个线程，当存在A,B，C,D四个线程时，会出现虚假唤醒现象！
    虚假唤醒：线程也可以唤醒，而不会被通知，中断或超时，即所谓的虚假唤醒。
    虽然这在实践中很少会发生，但应用程序必须通过测试应该使线程被唤醒的条
    件来防范，并且如果不满足条件则继续等待。换句话说，等待应该总出现在循
    环中。
    也就是说等待放在循环中可以防止虚假唤醒。参考boundedBufferProblem2
     */

}
class Data {
    private int num = 0;

    //+1操作
    public synchronized void increment() throws InterruptedException {
        //如果num不等于0,等待
        if (num != 0) {
            this.wait();
        }
        num++;
        System.out.println(Thread.currentThread().getName() + "=>" + num);
        //通知其他线程，我已+1完毕
        this.notifyAll();
    }

    //-1操作
    public synchronized void decrement() throws InterruptedException {
        //如果num等于0,等待
        if (num == 0) {
            this.wait();
        }
        num--;
        System.out.println(Thread.currentThread().getName() + "=>" + num);
        //通知其他线程，我已-1完毕
        this.notifyAll();
    }
}


